# 模拟图书管理系统
# 创建一个模拟图书管理系统，涉及多个类来模拟书籍、图书馆、借阅行为等。
# 定义一个书籍类
class Book:
    # 类变量，所有实例共享
    book_count = 0

    def __init__(self, title, author, genre):
        # 实例变量，每个实例独有
        self.title = title
        self.author = author
        self.genre = genre
        Book.book_count += 1  # 每次创建一个实例，类变量book_count自增1

    def __str__(self):
        # 用于打印书籍信息
        return f"《{self.title}》 作者: {self.author} 类别: {self.genre}"

    # 类方法：用于获取书籍的总数
    @classmethod
    def get_total_books(cls):
        return cls.book_count

    # 静态方法：不依赖实例或类，可以直接调用
    @staticmethod
    def is_valid_genre(genre):
        valid_genres = ["小说", "科幻", "历史", "儿童"]
        return genre in valid_genres


# 定义一个图书馆类
class Library:
    def __init__(self, name):
        self.name = name
        self.books = []  # 存储图书的列表

    def add_book(self, book):
        if not isinstance(book, Book):
            raise ValueError("只能添加Book类型的对象")
        self.books.append(book)

    def list_books(self):
        print(f"在{self.name}图书馆中有以下书籍：")
        for book in self.books:
            print(book)

    # 封装：提供借阅书籍的功能
    def borrow_book(self, book_title):
        for book in self.books:
            if book.title == book_title:
                self.books.remove(book)
                print(f"已借阅书籍: {book}")
                return book
        print("书籍未找到！")
        return None


# 定义一个借阅者类
class Borrower:
    def __init__(self, name):
        self.name = name
        self.borrowed_books = []  # 存储借阅的书籍

    def borrow(self, library, book_title):
        book = library.borrow_book(book_title)
        if book:
            self.borrowed_books.append(book)

    def return_book(self, library, book):
        if book in self.borrowed_books:
            self.borrowed_books.remove(book)
            library.add_book(book)
            print(f"{self.name} 已归还书籍: {book}")
        else:
            print(f"{self.name} 没有借阅过此书")


# 子类：借阅者专属的VIP借阅者
class VIPBorrower(Borrower):
    def __init__(self, name, vip_id):
        super().__init__(name)
        self.vip_id = vip_id

    # 重写借书方法，VIP借阅者可以借阅多本书
    def borrow(self, library, book_title):
        print(f"{self.name} (VIP) 正在借阅书籍: {book_title}")
        super().borrow(library, book_title)


# 示例程序
if __name__ == "__main__":
    # 创建一些书籍对象
    book1 = Book("Python编程", "John Doe", "科幻")
    book2 = Book("机器学习基础", "Jane Smith", "科幻")
    book3 = Book("历史的故事", "H.G. Wells", "历史")

    # 检查书籍的类别是否合法
    print(f"是否有效类别: {Book.is_valid_genre('科幻')}")

    # 创建图书馆对象并添加书籍
    my_library = Library("我的图书馆")
    my_library.add_book(book1)
    my_library.add_book(book2)
    my_library.add_book(book3)

    # 创建借阅者
    borrower = Borrower("Tom")
    borrower.borrow(my_library, "Python编程")
    borrower.return_book(my_library, book1)

    # 创建VIP借阅者
    vip_borrower = VIPBorrower("Alice", "VIP123")
    vip_borrower.borrow(my_library, "历史的故事")

    # 查看图书馆的书籍
    my_library.list_books()

    # 查看图书馆的总书籍数量
    print(f"当前图书馆的总书籍数量: {Book.get_total_books()}")

# 运行结果
# 是否有效类别: True
# Tom 正在借阅书籍: Python编程
# 已归还书籍: 《Python编程》 作者: John Doe 类别: 科幻
# Alice (VIP) 正在借阅书籍: 历史的故事
# 在我的图书馆中有以下书籍：
# 《机器学习基础》 作者: Jane Smith 类别: 科幻
# 《历史的故事》 作者: H.G. Wells 类别: 历史
# 当前图书馆的总书籍数量: 3

# 1. 类与对象
# ● Book 是一个类，表示书籍的对象，每个书籍对象有 title、author、genre 等实例变量。
# ● Library 是一个图书馆类，表示图书馆，里面有一组 Book 对象，管理书籍的借阅。
# ● Borrower 是借阅者类，表示一个借书的人员，具有借阅和归还书籍的功能。
# ● VIPBorrower 是 Borrower 类的子类，表示VIP借阅者，具有特殊的借阅权限（可以借更多书籍）。
# 2. 实例变量与类变量
# ● Book 类中的 book_count 是一个类变量，用来跟踪图书的总数。每创建一个 Book 对象时，类变量 book_count 会增加。
# ● title、author、genre 是实例变量，每个书籍对象都有不同的值。
# 3. 方法
# ● __init__ 是构造方法，用来初始化对象时设置初始值。
# ● __str__ 是用于打印对象时调用的方法，它返回书籍的格式化字符串。
# ● add_book 和 list_books 是 Library 类的方法，分别用于添加书籍和列出所有书籍。
# ● borrow_book 是 Library 类中的封装方法，控制书籍借阅的行为（如：检查是否有该书籍、执行借阅等）。
# 4. 类方法与静态方法
# ● get_total_books 是 Book 类的类方法，用于获取当前所有书籍的总数。它通过 @classmethod 装饰器定义。
# ● is_valid_genre 是静态方法，用于检查给定的书籍类别是否有效。它通过 @staticmethod 装饰器定义，表示该方法与类的状态无关，不依赖于实例变量或类变量。
# 5. 继承与多态
# ● VIPBorrower 类继承了 Borrower 类，扩展了借阅功能。重写了 borrow 方法，表示VIP借阅者可以借阅书籍时打印特定信息。
# ● 在调用 vip_borrower.borrow 时，Python 会根据实际对象的类型（VIPBorrower）执行相应的方法，表现出多态。
# 6. 封装
# ● Library 类封装了 borrow_book 方法，用于处理借阅的具体逻辑，用户只需要调用 borrow 方法，不需要知道内部实现的细节。
#
# 总结
# ● 面向对象的基本概念：包括类和对象、实例变量和类变量、方法（实例方法、类方法、静态方法）等。
# ● 继承和多态：通过继承 Borrower 类扩展 VIPBorrower 类的功能，重写了借书方法，展示了多态的特性。
# ● 封装：通过封装方法控制图书借阅的行为，用户只需调用接口，不需要关心内部的实现。

# 扩展：魔术方法
# 在 Python 中，以双下划线 __ 开头和结尾的方法被称为“魔术方法”或“特殊方法”。这些方法并不是每个类中都默认存在的，而是由开发者根据需要定义的。它们主要用于实现特定的行为，使得类可以与 Python 的内置语法和功能进行交互。常见的魔术方法包括：
# ● __init__(self, ...): 初始化对象时调用，用于设置对象的初始状态。
# ● __str__(self): 定义对象被转换为字符串时的输出格式，例如在 print() 函数中使用。
# ● __repr__(self): 定义对象的“官方”字符串表示形式，通常用于调试。
# ● __len__(self): 定义对象的长度，例如在 len() 函数中使用。
# ● __getitem__(self, key): 允许对象像字典或列表一样通过索引访问元素。
# ● __setitem__(self, key, value): 允许对象像字典或列表一样通过索引设置元素。
# ● __call__(self, ...): 允许对象像函数一样被调用。
# ● __eq__(self, other): 定义对象之间的相等比较操作。
# ● __add__(self, other): 定义对象之间的加法操作。